package download.dx.com.httpdownload;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * Created by jwaoo on 2017/7/18.
 */

public class DownloadManager {
    public static final int STATE_WATTING = 0;
    public static final int STATE_DOWNING = 1;//下载中
    public static final int STATE_FINISH = 2;//完成下载
    public static final int STATE_PAUSE = 3;//暂停
    public static final int STATE_FAILED = 4;//下载失败
    public static final int STATE_EXISTS = 5;//文件已存在
    public static final int STATE_NETWORK_DISSCONECTED = 6;//文件已存在
    private final static int maxQueue = 5;
    private static IDownloadModel downloadModel;
    private static BlockingQueue<DownloadTask> queueExecute = new LinkedBlockingQueue<>(maxQueue);
    private static Queue<DownloadTask> queueWatting = new LinkedList<>();
    private static Queue<DownloadTask> queueFailed = new LinkedList<>();
    private static Queue<DownloadTask> queueFinish = new LinkedList<>();
    private static Map<String,DownloadTask> map = new HashMap<>();

    /**
     * 初始化下载相关数据库操作
     * @param model
     */
    public static void initDownloadDB(IDownloadModel model){
        downloadModel = model;
        List<DownloadInfo> list = downloadModel.getDownloadInfo();
        for (DownloadInfo info: list) {
            addTask(info);
        }
    }


    /**
     * 开始下载
     * @param info
     */
    public static void startDownload(DownloadInfo info){
        addTask(info);
        excecute();
    }

    /**
     * 暂停下载
     * @param info
     */
    public static void downloadStop(DownloadInfo info) {
        try {
            String key = info.getKey();
            if (map.containsKey(key)) {
                map.get(key).pause();
                onDownloadStop(map.get(key));
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }

    /**
     * 重新下载（暂停--下载）
     * @param info
     */
//    public static void reStart(DownloadInfo info){
//        if (map.containsKey(info.getKey())){
//            map.get(info.getKey()).getInfo().setState(STATE_WATTING);
//            excecute();
//        }
//    }

    /**
     * 下载失败的文件重新下载
     * @param info
     */
//    public static void downLoadFailedFile(DownloadInfo info){
//        if (map.containsKey(info.getKey())){
//            info.setState(STATE_WATTING);
//            DownloadTask task = map.get(info.getKey());
//            queueWatting.offer(task);
//            queueFailed.remove(task);
//            excecute();
//        }
//    }

    /**
     * 取消下载
     * @param info
     */
    public static void canecl(DownloadInfo info){
        if (downloadModel != null) downloadModel.deleteDownloadInfo(info);
    }


    /**
     *返回下载任务集合
     * @return
     */
    public static List<DownloadInfo> getAllDownloadInfo(){
        List<DownloadInfo> list = new ArrayList<>();
        Set<DownloadTask> set = (Set)map.values();
        Iterator<DownloadTask> iterable = set.iterator();
        while (iterable.hasNext()){
            list.add(iterable.next().getInfo());
        }
        return list;
    }

    /**
     * 设置下载回掉
     * @param info
     * @param downloadListener
     */
    public static void setDownloadListener(DownloadInfo info,OnDownloadListener downloadListener){
        if (map.containsKey(info.getKey())){
            map.get(info.getKey()).setOnDownloadListener(downloadListener);
        }
    }


    /**
     * 添加下载任务到等待队列中
     * @param info
     */
    public static void addTask(DownloadInfo info){
        if (!map.containsKey(info.getKey())){
            DownloadTask task = new DownloadTask(info);
            switch (info.getState()){
                case DownloadManager.STATE_DOWNING:
                case DownloadManager.STATE_NETWORK_DISSCONECTED:
                    info.setState(STATE_WATTING);
                    if (!queueExecute.offer(task)) {
                        queueWatting.offer(task);
                    }
                    break;
                case DownloadManager.STATE_FAILED:
                    queueFailed.offer(task);
                    break;
                case DownloadManager.STATE_FINISH:
                    queueFinish.offer(task);
                    break;
                case DownloadManager.STATE_PAUSE:
                case DownloadManager.STATE_WATTING:
                    info.setState(DownloadManager.STATE_WATTING);
                    queueWatting.offer(task);
                    break;
            }
            map.put(info.getKey(),task);
            if (downloadModel != null) downloadModel.saveDownloadInfo(info);
        }else {
            switch (info.getState()){
                case DownloadManager.STATE_PAUSE:
                    map.get(info.getKey()).getInfo().setState(STATE_WATTING);
                    break;
                case DownloadManager.STATE_FAILED:
                    info.setState(STATE_WATTING);
                    DownloadTask task = map.get(info.getKey());
                    queueWatting.offer(task);
                    queueFailed.remove(task);
                    break;
            }


        }
    }


    public static void downloadFinish (DownloadTask task) throws Exception{
        queueFinish.add(task);
        if (downloadModel != null) downloadModel.updateDownloadInfo(task.getInfo());
        excecuteNewTask(task);
    }

    public static void downloadFailed(DownloadTask task){
        try{
            queueFailed.add(task);
            excecuteNewTask(task);
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }

    public static void downloadStopByNetWork(DownloadTask task){
        if (downloadModel != null) downloadModel.updateDownloadInfo(task.getInfo());
    }

    /**
     * 执行批量下载
     */
    public static void excecute(){
        try{
            for (int i = 0; i < maxQueue; i ++){
                if (!queueWatting.isEmpty() && queueExecute.offer(queueWatting.peek())){
                    queueWatting.remove();
                }
            }
            for (DownloadTask task : queueExecute) {
                task.start();
                if (downloadModel != null) downloadModel.updateDownloadInfo(task.getInfo());
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }

    private static synchronized void excecuteNewTask(DownloadTask task) throws Exception{
        queueExecute.remove(task);
        DownloadTask newTask = queueWatting.peek();
        if (!queueWatting.isEmpty() && newTask.getInfo().getState() != DownloadManager.STATE_PAUSE && queueExecute.offer(newTask)){
            newTask.start();
            queueWatting.remove(newTask);
            if (downloadModel != null) downloadModel.updateDownloadInfo(task.getInfo());
        }
    }



    public static void onDownloadStop(DownloadTask task) throws Exception{
        if (downloadModel != null) downloadModel.updateDownloadInfo(task.getInfo());
        queueWatting.add(task);
        excecuteNewTask(task);
    }


}
